<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

    <button id="btn">eventBus</button>
    <button id="btn2">防抖</button>
    <button id="btn3">节流</button>

    <script>
        // 实现onWatch来监听

        // Reflect的作用是啥 
        // 它是一个对象，上面有很多方法，这些方法都是对目标对象的操作，但是它不会改变目标对象，只是返回一个结果

        const onWatch = (obj, setBind, getLog) => {
            return new Proxy(obj, {
                get(target, property, receiver) {
                    getLog(target, property)
                    return Reflect.get(target, property, receiver)
                },
                set(target, property, value, receiver) {
                    setBind(target, property, value)
                    return Reflect.set(target, property, value, receiver)
                }
            })
        }

        const aaa = {
            name: 'aaa',
            age: 18
        }

        const aaaProx = onWatch(aaa, (target, property, value) => {
            console.log('set', target, property, value)
        }, (target, property) => {
            console.log('get', target, property)
        })

        console.log(aaaProx.name)

        setTimeout(() => {
            aaaProx.name = 'bbb'
        }, 2000)


        class EventBus {
            constructor() {
                this.events = {}
            }
            on(name, fn) {
                if (!this.events[name]) {
                    this.events[name] = []
                }
                this.events[name].push(fn)
            }
            emit(name, ...args) {
                if (this.events[name]) {
                    this.events[name].forEach(fn => fn(...args))
                }
            }
            off(name, fn) {
                if (this.events[name]) {
                    this.events[name] = this.events[name].filter(f => f !== fn)
                }
            }
            once(name, fn) {
                const fnTemp = (...args) => {
                    fn(...args)
                    this.off(name, fnTemp)
                }
                this.on(name, fnTemp)
            }
        }


        const bus = new EventBus()
        bus.on('test', (...args) => {
            console.log('test', args)
        })

        document.getElementById('btn').addEventListener('click', () => {
            bus.emit('test', 'hello', 123)
        })

        // 防抖
        const debounce = (fn, delay, immediate = false) => {
            let timer = null;
            return (...args) => {
                if (timer) clearTimeout(timer);
                let callNow = immediate && !timer;
                if (callNow) {
                    fn(...args);
                }
                timer = setTimeout(() => {
                    fn(...args);
                }, delay);
            }
        }
        const throttle = (fn, delay, immediate = false) => {
            let timer = null;
            return (...args) => {
                if (timer) return;
                const callNow = immediate && !timer;
                if (callNow) {
                    fn(...args);
                }
                timer = setTimeout(() => {
                    fn(...args);
                    clearTimeout(timer);
                    timer = null;
                }, delay);
            }
        }

        document.getElementById('btn2').addEventListener('click', debounce(() => {
            console.log('防抖')
        }, 1000, false))
        document.getElementById('btn3').addEventListener('click', throttle(() => {
            console.log('节流')
        }, 1000, false))

        const deepClone = (obj, hash = new WeakMap()) => {
            if (typeof obj !== 'object' || obj === null) return obj;
            if (obj instanceof Date) return new Date(obj);
            if (obj instanceof RegExp) return new RegExp(obj);
            if (hash.has(obj)) return hash.get(obj);
            const cloneObj = new obj.constructor();
            hash.set(obj, cloneObj);
            for (const key in obj) {
                if (obj.hasOwnProperty(key)) {
                    cloneObj[key] = deepClone(obj[key], hash);
                }
            }
            return cloneObj;
        }

        function myInstanceOf(left, right) {
            let rightPrototype = right.prototype;
            left = left.__proto__;
            while (left != null) {
                if (left === rightPrototype) {
                    return true;
                }
                left = left.__proto__;
            }
            return false;
        }

        const obj = {
            name: 'aaa',
            age: 18,
            children: {
                name: 'bbb',
                age: 10
            }
        }
        const obj2 = deepClone(obj);

        console.log(myInstanceOf(obj2, Array));

    </script>

</body>

</html>